package com.xiyi.shouxin.dao;

import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
import org.springframework.util.StringUtils;

import com.xiyi.shouxin.exception.CommonException;
import com.xiyi.shouxin.exception.ErrorCode;
import com.xiyi.shouxin.utils.BeanUtil;

/*
 * 使用该工具，实体类必须通过注解@Table和@Column指定表名和字段
 */
public class JdbcPreparedStatement<T> {
    private String tableName;
    private String queryColumns;
    private Map<String, String> fieldColumnMap = new HashMap<>();

    public JdbcPreparedStatement(Class<T> clazz) {
        init(clazz);
    }

    private void init(Class<T> clazz) {
        Table table = clazz.getAnnotation(Table.class);
        if (table == null) {
            return;
        }
        this.tableName = "`" + table.value() + "`";
        List<String> columns = new ArrayList<>();
        // 获取具有get方法的字段
        List<Field> fields = BeanUtil.findGetMethodsField(clazz);
        for (Field field : fields) {
            Column column = field.getAnnotation(Column.class);
            if (column == null) {
                continue;
            }
            String value = column.value();
            if (StringUtils.hasText(value)) {
                String col = "`" + value + "`";
                columns.add(col);
                this.fieldColumnMap.put(field.getName(), col);
            }
        }
        if (!columns.isEmpty()) {
            this.queryColumns = String.join(",", columns);
        }
    }

    /*
     * 获取sql类型
     */
    private int getSqlType(Class<?> clazz) {
        if (clazz.equals(Integer.class)) {
            return Types.INTEGER;
        }
        if (clazz.equals(Long.class)) {
            return Types.BIGINT;
        }
        if (clazz.equals(String.class)) {
            return Types.VARCHAR;
        }
        if (clazz.equals(Float.class)) {
            return Types.DECIMAL;
        }
        if (clazz.equals(Double.class)) {
            return Types.DECIMAL;
        }
        if (clazz.equals(Timestamp.class)) {
            return Types.TIMESTAMP;
        }
        return Types.VARCHAR;
    }

    public String GetTableName() {
        return tableName;
    }

    public String GetQueryColumns() {
        return queryColumns;
    }

    public String GetColumnName(String fieldName) {
        return this.fieldColumnMap.get(fieldName);
    }

    /*
     * 生成插入sql
     */
    public JdbcStatementCreator genertateCreateSql(T t) throws Exception {
        List<Field> fields = BeanUtil.findGetMethodsField(t.getClass());

        List<Object> args = new ArrayList<>();
        List<Integer> types = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        StringBuilder sb = new StringBuilder("INSERT INTO ");

        sb.append(tableName);
        for (Field field : fields) {
            String column = this.fieldColumnMap.get(field.getName());
            if (column == null) {
                continue;
            }
            field.setAccessible(true);
            Object value = field.get(t);
            if (value != null) {
                columns.add(column);
                args.add(value);
                int tp = getSqlType(field.getType());
                types.add(tp);
            }
        }
        if (!columns.isEmpty()) {
            sb.append(" (");
            sb.append(String.join(",", columns));
            sb.append(") ");
        }
        sb.append(" VALUES(");
        if (args.isEmpty()) {
            throw new CommonException(ErrorCode.DATAWRONG);
        }
        for (int i = 0; i < args.size(); i++) {
            sb.append("?");
            if (i < args.size() - 1) {
                sb.append(",");
            }
        }
        sb.append(")");
        JdbcStatementCreator creator = new JdbcStatementCreator(sb.toString(), args, types);
        return creator;
    }

    /*
     * 生成根据id更新sql
     */
    public JdbcStatementCreator genertateUpdateByIdSql(Long id, T t) throws Exception {
        List<Field> fields = BeanUtil.findGetMethodsField(t.getClass());

        List<Object> args = new ArrayList<>();
        List<Integer> types = new ArrayList<>();
        List<String> sets = new ArrayList<>();
        StringBuilder sb = new StringBuilder("UPDATE ");

        sb.append(tableName);
        for (Field field : fields) {
            String column = this.fieldColumnMap.get(field.getName());
            if (column == null || "ID".equals(column.toUpperCase())) {
                continue;
            }
            field.setAccessible(true);
            Object value = field.get(t);
            if (value != null) {
                String set = column + " = ? ";
                sets.add(set);
                args.add(value);
                int tp = getSqlType(field.getType());
                types.add(tp);
            }
        }
        if (!sets.isEmpty()) {
            sb.append(" SET ");
            sb.append(String.join(",", sets));
            sb.append(" ");
        }
        sb.append(" WHERE id = ?");
        args.add(id);
        types.add(Types.BIGINT);
        if (args.size() == 1) {
            throw new CommonException(ErrorCode.DATAWRONG);
        }
        JdbcStatementCreator creator = new JdbcStatementCreator(sb.toString(), args, types);
        return creator;
    }

}
